#include "QSPrecompiledHeaders.h"
#include "QSOISInputSystem.h"
#include <OIS/OIS.h>

using namespace QS;


static Key::Enum keys[256];
static Button::Enum buttons[10];

static void initOISKeys()
{
	//letters
	keys[OIS::KC_A] = Key::A;
	keys[OIS::KC_B] = Key::B;
	keys[OIS::KC_C] = Key::C;
	keys[OIS::KC_D] = Key::D;
	keys[OIS::KC_E] = Key::E;
	keys[OIS::KC_F] = Key::F;
	keys[OIS::KC_G] = Key::G;
	keys[OIS::KC_H] = Key::H;
	keys[OIS::KC_I] = Key::I;
	keys[OIS::KC_J] = Key::J;
	keys[OIS::KC_K] = Key::K;
	keys[OIS::KC_L] = Key::L;
	keys[OIS::KC_M] = Key::M;
	keys[OIS::KC_N] = Key::N;
	keys[OIS::KC_O] = Key::O;
	keys[OIS::KC_P] = Key::P;
	keys[OIS::KC_Q] = Key::Q;
	keys[OIS::KC_R] = Key::R;
	keys[OIS::KC_S] = Key::S;
	keys[OIS::KC_T] = Key::T;
	keys[OIS::KC_U] = Key::U;
	keys[OIS::KC_V] = Key::V;
	keys[OIS::KC_W] = Key::W;
	keys[OIS::KC_X] = Key::X;
	keys[OIS::KC_Y] = Key::Y;
	keys[OIS::KC_Z] = Key::Z;

	//numbers
	keys[OIS::KC_0] = Key::Num0;
	keys[OIS::KC_1] = Key::Num1;
	keys[OIS::KC_2] = Key::Num2;
	keys[OIS::KC_3] = Key::Num3;
	keys[OIS::KC_4] = Key::Num4;
	keys[OIS::KC_5] = Key::Num5;
	keys[OIS::KC_6] = Key::Num6;
	keys[OIS::KC_7] = Key::Num7;
	keys[OIS::KC_8] = Key::Num8;
	keys[OIS::KC_9] = Key::Num9;

	//punctuation
	keys[OIS::KC_COMMA]		= Key::Comma;
	keys[OIS::KC_EQUALS]	= Key::Equals;
	keys[OIS::KC_MINUS]		= Key::Minus;
	keys[OIS::KC_PERIOD]	= Key::Period;
	keys[OIS::KC_SEMICOLON]	= Key::Semicolon;
	keys[OIS::KC_APOSTROPHE]= Key::Apostrophe;
	keys[OIS::KC_LBRACKET]	= Key::LeftBracket;
	keys[OIS::KC_RBRACKET]	= Key::RightBracket;

	//navigation
	keys[OIS::KC_UP]		= Key::UpArrow;
	keys[OIS::KC_DOWN]		= Key::DownArrow;
	keys[OIS::KC_LEFT]		= Key::LeftArrow;
	keys[OIS::KC_RIGHT]		= Key::RightArrow;
	keys[OIS::KC_INSERT]	= Key::Insert;
	keys[OIS::KC_HOME]		= Key::Home;
	keys[OIS::KC_END]		= Key::End;
	keys[OIS::KC_PGUP]		= Key::PageUp;
	keys[OIS::KC_PGDOWN]	= Key::PageDown;

	//function keys
	keys[OIS::KC_F1]		= Key::F1;
	keys[OIS::KC_F2]		= Key::F2;
	keys[OIS::KC_F3]		= Key::F3;
	keys[OIS::KC_F4]		= Key::F4;
	keys[OIS::KC_F5]		= Key::F5;
	keys[OIS::KC_F6]		= Key::F6;
	keys[OIS::KC_F7]		= Key::F7;
	keys[OIS::KC_F8]		= Key::F8;
	keys[OIS::KC_F9]		= Key::F9;
	keys[OIS::KC_F10]		= Key::F10;
	keys[OIS::KC_F11]		= Key::F11;
	keys[OIS::KC_F12]		= Key::F12;

	//editing
	keys[OIS::KC_RETURN]	= Key::Enter;
	keys[OIS::KC_BACK]		= Key::Backspace;
	keys[OIS::KC_DELETE]	= Key::Delete;
	keys[OIS::KC_SPACE]		= Key::Space;
	keys[OIS::KC_ESCAPE]	= Key::Escape;

	//meta
	keys[OIS::KC_LSHIFT]	= Key::Shift;
	keys[OIS::KC_RSHIFT]	= Key::Shift;
	keys[OIS::KC_LCONTROL]	= Key::Control;
	keys[OIS::KC_RCONTROL]	= Key::Control;
}

static void initOISButtons()
{
	buttons[OIS::MB_Left]	= Button::Mouse1;
	buttons[OIS::MB_Right]	= Button::Mouse2;
	buttons[OIS::MB_Middle] = Button::Mouse3;
}


bool OISInputSystem::mouseMoved( const OIS::MouseEvent& arg)
{
	MouseEventArgs* e = new MouseEventArgs(false, arg.state.X.rel, arg.state.Y.rel);
	mEngine->getEventSystem()->queueEvent(Event(EventType::MouseMove, e));
	return true;
}

bool OISInputSystem::mousePressed( const OIS::MouseEvent&, OIS::MouseButtonID id )
{
	MouseEventArgs* e = new MouseEventArgs(true, 0,0, buttons[id]);
	mEngine->getEventSystem()->queueEvent(Event(EventType::MouseDown, e));
	return true;
}

bool OISInputSystem::mouseReleased( const OIS::MouseEvent&, OIS::MouseButtonID id )
{
	MouseEventArgs* e = new MouseEventArgs(false, 0,0, buttons[id]);
	mEngine->getEventSystem()->queueEvent(Event(EventType::MouseUp, e));
	return true;
}

bool OISInputSystem::keyPressed( const OIS::KeyEvent &arg )
{
	KeyEventArgs* e = new KeyEventArgs(true, arg.text, keys[arg.key]);
	mEngine->getEventSystem()->queueEvent(Event(EventType::KeyDown, e));
	return true;
}

bool OISInputSystem::keyReleased( const OIS::KeyEvent &arg )
{
	KeyEventArgs* e = new KeyEventArgs(false, arg.text, keys[arg.key]);
	mEngine->getEventSystem()->queueEvent(Event(EventType::KeyUp, e));
	return true;
}

void OISInputSystem::initialize()
{
	if (mInputManager)
		//already initialized
		return;

	initOISButtons();
	initOISKeys();

	mInputManager = OIS::InputManager::createInputSystem(mEngine->getRenderSystem()->getWindowHandle());
	mKeyboard = static_cast<OIS::Keyboard*>(mInputManager->createInputObject(OIS::OISKeyboard, true));
	mMouse = static_cast<OIS::Mouse*>(mInputManager->createInputObject(OIS::OISMouse, true));

	mMouse->setEventCallback(this);
	mKeyboard->setEventCallback(this);
}

void OISInputSystem::shutdown()
{
	if (!mInputManager)
		//never initialized, so nothing to shut down
		return;

	mInputManager->destroyInputObject(mMouse);
	mInputManager->destroyInputObject(mKeyboard);
	OIS::InputManager::destroyInputSystem(mInputManager);
	
	mInputManager = 0;
	mMouse = 0;
	mKeyboard = 0;	
}

void OISInputSystem::update()
{
	if (mMouse && mKeyboard)
	{
		mMouse->capture();
		mKeyboard->capture();
	}
}